import {NbGoStep} from '../NbGoStep.js';
import {isCrLabelApproved, waitForCondition} from '../GoUtils.js';
import {StrUtil} from '../../../utils/StrUtil.js';
import {newGitLabClient} from '../../../utils/GitLabClient.js';

export class FeatureTagCrStep extends NbGoStep {
    constructor() {
        super({
            key: 'featureTagCr',
            name: 'Feature-Tag CR',
            description: '校验并补齐 CR 标签'
        });
    }

    async shouldSkip(context) {
        const {pipeline, opsClient} = context;
        const {flowId, flowType} = pipeline.getFlowIdentity();
        const {flatten} = await pipeline.getFlowApps(true);
        const crData = await opsClient.getCrData(flowId, flowType);
        const needCrApps = flatten.filter(app => app.isCr);
        const pending = [];
        for (const app of needCrApps) {
            const entry = crData?.[app.appName];
            if (!entry || !isCrLabelApproved(entry)) {
                pending.push({
                    ...app,
                    crEntry: entry
                });
            }
        }
        context.cache.featureCrPending = pending;
        if (pending.length === 0) {
            return {
                skip: true,
                reason: '所有需 CR 的项目均已通过',
                metadata: {
                    checkedAt: new Date().toISOString()
                }
            };
        }
        return {skip: false};
    }

    async execute(context) {
        const {logger, pipeline, opsClient, globalOpsFile} = context;
        const pending = context.cache.featureCrPending || [];
        if (pending.length === 0) {
            return {
                crApps: []
            };
        }
        const privateToken = globalOpsFile.read('git_private_token');
        if (StrUtil.isNull(privateToken)) {
            throw new Error('缺少 git_private_token，请在全局配置中维护 GitLab 私有令牌');
        }
        const gitlabClient = newGitLabClient(privateToken, false);
        const {flowId, flowType} = pipeline.getFlowIdentity();
        const crHandled = [];

        for (const item of pending) {
            const branch = item.raw?.name;
            const repoId = item.raw?.repo_id;
            if (StrUtil.isNull(branch) || !repoId) {
                throw new Error(`${item.appName} 缺少 CR 依赖的分支或 repoId 信息`);
            }
            logger.info(`处理 CR：${item.appName} 分支 ${branch}`);
            const crEntry = item.crEntry;
            if (!crEntry || StrUtil.isEmptyObject(crEntry)) {
                // 先调用 ops 接口生成 CR URL
                if (item.flowAppId) {
                    await opsClient.getCrUrl(item.flowAppId);
                }
                await gitlabClient.mergeRequestsAndCr(repoId, {
                    source_branch: branch,
                    target_branch: `${branch}-release`,
                    title: `${branch} → ${branch}-release`,
                    labels: '1.CR通过'
                });
                crHandled.push(item.appName);
                continue;
            }
            const webUrl = crEntry.web_url;
            const mrId = StrUtil.getMrId(webUrl);
            if (!mrId) {
                await gitlabClient.mergeRequestsAndCr(repoId, {
                    source_branch: branch,
                    target_branch: `${branch}-release`,
                    title: `${branch} → ${branch}-release`,
                    labels: '1.CR通过'
                });
                crHandled.push(item.appName);
                continue;
            }
            await gitlabClient.mergeRequestsAndCrByMrId(repoId, mrId, {
                labels: '1.CR通过'
            });
            crHandled.push(item.appName);
        }

        try {
            await waitForCondition(async () => {
                const crData = await opsClient.getCrData(flowId, flowType);
                return crHandled.every(appName => isCrLabelApproved(crData?.[appName]));
            }, {timeoutMs: this.timeoutMs, intervalMs: 10_000});
        } catch (error) {
            throw new Error(`CR 打标未在限定时间内完成，请手动处理 (${error.message})`);
        }

        return {
            crApps: crHandled,
            finishedAt: new Date().toISOString()
        };
    }
}
